[SAP ABAP开发技术总结]逻辑数据库

LDB不常用,但学好它可以写出共用封装好的查询

6.   逻辑数据库

6.1.  组成

SLDB

image049 

6.2.  结构

image050

决定了数据从哪些数据库表、视图中提取数据以及这些表、视图之间的层次关系(层次将决定数据读取的顺序

数据库表T类型节点)、词典类型S类型节点),比如节点类型为S的节点:root_node,数据类型为INT4

image051

LDB的数据库程序的最TOP Include文件包括以下语句:

 NODES root_node.

另外,在LDB数据库程序包括了以下过程:

FORM put_root_node.
 
DO 10 TIMES.
    root_node
= sy-index.
   
PUT root_node."会去调用报表程序中的 GET root_node. 事件块
 
ENDDO.
ENDFORM.

在与此LDB关连的可执行程序:

image052

REPORT demo_nodes.
NODES root_node.
GET root_node. 
 
WRITE root_node.

6.3.  选择屏幕(Selections

定义了LDB的选择屏幕,该选择屏幕的布局由LDB的结构决定,一旦将LDB链接到报表程序后,该选择屏幕会自动嵌入到默认选择屏幕1000

image050[1]

第一次进入选择屏幕程序时,系统会为每个LDB生成一个名为DB<LDB_Name>SELInclude选择屏幕包含文件:

image053

image054

 

而且,所有表(T类型的节点)的主键都会出现在SELECT-OPTIONS语句中,成为屏幕选择字段(自动生成的需要去掉注释,并设置屏幕选择字段名):

image055

除了上面自动生成的LDB屏幕字段外,还可以使用以下面语句来扩展LDB选择屏幕:

6.3.1.   PARAMETERS屏幕参数扩充

增加一个单值输入条件框(PARAMETERS语句一般在LDB中只用于除节点表外的非表字段屏幕参数),在PARAMETERS语句中必须使用选项FOR NODE XXX 或者 FOR TABLE XXX 来指定这些扩展参数属性哪个节点的:PARAMETERS CITYTO LIKE SPFLI-CITYTO FOR NODE SPFLI.

注:SELECT-OPTIONS没有FOR NODE这样的用法

具体请参数后面的LDB选择屏幕章节

6.3.2.   SELECTION-SCREEN格式化屏幕

使用SELECTION-SCREEN语句来格式化屏幕

具体请参数后面的LDB选择屏幕章节

6.3.3.   DYNAMIC SELECTIONS动态选择条件

SELECTION-SCREEN DYNAMIC SELECTIONS FOR NODE|TABLE <node>.用来开启<node>节点的LDB dynamic selections功能,即可以在WHERE从句中使用动态选择条件(形如:…WHERE field1 = value1 AND (条件内表) …只有开启了动态选择条件功能的表,才可以在LDB数据库程序中对表进行动态选择条件处理。下面是数据库程序中如何使用动态选择条件示例:

image056

上面LDB数据库程序中的RSDS_WHERE条件内表来自RSDS类型组,相应源码如下:

image057

另外,上面LDB数据库程序中要能从DYN_SEL-CLAUSES内表读取数据,则必须在LDB选择屏幕里开启相应节点的动态选择条件:

image058

其中,DYN_SEL-CLAUSES内表行结构如下:

image059

6.3.3.1.            DYN_SEL

PUT_<node> Form中的SELECT语句中Where从句如果要使用 DYNAMIC SELECTIONS 动态选择条件时,需要用到变量DYN_SEL,该数据对象是在LDB数据库程序中自动生成的,其类型如下(注:不必在LDB程序中加入下面代码行就可以直接使用DYN_SEL):

TYPE-POOLS RSDS.
DATA DYN_SEL TYPE RSDS_TYPE.

你不必在程序中定义它就可以直接使用,但它只能在LDB数据库程序中使用,而不能用在报表程序中RSDS_TYPE数据类型是在类型组RSDS中定义的:

TYPE-POOL RSDS .
TYPES: RSDS_WHERE_TAB LIKE RSDSWHERE OCCURS 5."RSDSWHERE 类型为C(72)
TYPES: BEGIN OF RSDS_WHERE,
         TABLENAME
LIKE RSDSTABS-PRIM_TAB,
         WHERE_TAB
TYPE RSDS_WHERE_TAB,
      
END OF RSDS_WHERE.
TYPES
: RSDS_TWHERE TYPE RSDS_WHERE OCCURS 5.

TYPES: BEGIN OF RSDS_TYPE,
        
CLAUSES TYPE RSDS_TWHERE,
         TEXPR  
TYPE RSDS_TEXPR,

        
TRANGE  TYPE RSDS_TRANGE,
      
END   OF RSDS_TYPE.

RSDS_TYPE是一个深层结构的结构体,里面三个字段都是内表类型,其中以下两个字段重要:

6.3.3.1.1.     RSDS_TYPE-CLAUSES

Where从句部分,实则存储了可直接用在WHERE从句中的动态Where条件内表,可以在Where动态语句中直接使用,该组件为内表,存储了用户在选择屏幕上选择的LDB动态选择字段

 

每个被选择的LDB屏幕动态选择字段都会形成一个条件,并存储到RSDS_TYPE-CLAUSES-WHERE_TAB内表中,WHERE_TAB内表中存储的就是直接可以用在Where从句中的动态选择条件中

 

每个表(节点)都会有自己的CLAUSES-WHERE_TAB动态条件内表,这是通过CLAUSES-TABLENAME区别的

 

现假设有名为 ZHK LDBSCARR为该LDB的根节点,且仅有SPFLI一个子节点。LDB选择屏幕 Include文件DBZHKSEL内容如下:

SELECT-OPTIONS S_CARRID FOR SCARR-CARRID.
SELECT-OPTIONS S_CONNID FOR SPFLI-CONNID.

"需要先开始动态选择条件功能
SELECTION-SCREEN DYNAMIC SELECTIONS FOR TABLE SCARR.

LDB数据库程序SAPDBZHK中,PUT_SCARR过程中使用dynamic selection的过程如下:

FORM PUT_SCARR.
 
STATICS: DYNAMIC_SELECTIONS TYPE RSDS_WHERE,FLAG_READ. "定义成静态类型的是防止再次进入此Form时,再次初始化DYNAMIC_SELECTIONS结构,即只执行一次初始化代码
  IF FLAG_READ = SPACE.
    DYNAMIC_SELECTIONS
-TABLENAME = 'SCARR'.
   
READ TABLE DYN_SEL-CLAUSES WITH KEY DYNAMIC_SELECTIONS-TABLENAME INTO DYNAMIC_SELECTIONS.
    FLAG_READ
= 'X'.
 
ENDIF.
 
SELECT * FROM
SCARR  WHERE CARRID IN S_CARRID AND (DYNAMIC_SELECTIONS-WHERE_TAB). "使用动态Where条件
   
PUT SCARR.
 
ENDSELECT
.
ENDFORM.

6.3.3.1.2.     RSDS_TYPE-TRANGE

该字段是一个内表,存储了CLAUSES的原数据,CLAUSES内表里的数据实质就是来源于TRANGE内表,只是CLAUSES已经将每个表字段的条件拼接成了一个或多个条件串了(形如:“XXX字段 = XXX条件”),但是TRANGE内表与RANGES tables相同,存储的是字段最原始的条件值,使用时,在WHERE从句中使用 IN 关键字来使用这些条件值(这与SELECT-OPTIONS类型的屏幕参数用户是完全一样的)。

但是,使用TRANGE没有直接使用CLAUSES灵活,因为使用TRANGE时,WHERE从句里的条件表字段需要事先写好,这实质上不是动态条件了,可以参考以下实例,与上面CLAUSES用法相比就更清楚了:现修改上面的示例:

SELECT-OPTIONS S_CARRID FOR SCARR-CARRID.
SELECT-OPTIONS S_CONNID FOR SPFLI-CONNID.

"需要先开始动态选择条件功能
SELECTION-SCREEN DYNAMIC SELECTIONS FOR TABLE SCARR.

LDB数据库程序SAPDBZHK中,PUT_SCARR过程中使用dynamic selection的过程如下:

FORM PUT_SCARR.
  STATICS: DYNAMIC_RANGES TYPE RSDS_RANGE, "存储某个表的所有屏幕字段的Ranges
          
DYNAMIC_RANGE1 TYPE RSDS_FRANGE,"存储某个屏幕字段的Ranges
         
DYNAMIC_RANGE2 TYPE RSDS_FRANGE,
          FLAG_READ."确保DYN_SEL只读取一次
 
IF FLAG_READ = SPACE.
    DYNAMIC_RANGES
-TABLENAME = 'SCARR'
.
    "先取出 SCARR 表的所有屏幕字段的Ranges
   
READ TABLE DYN_SEL-TRANGE WITH KEY DYNAMIC_RANGES-TABLENAME                              INTO DYNAMIC_RANGES.
    "再读取出属于某个字段的Ranges
    DYNAMIC_RANGE1
-FIELDNAME = 'CARRNAME'.
   
READ TABLE DYNAMIC_RANGES-FRANGE_T WITH KEY DYNAMIC_RANGE1-FIELDNAME
                             
INTO DYNAMIC_RANGE1.

    DYNAMIC_RANGE2
-FIELDNAME = 'CURRCODE'.
   
READ TABLE DYNAMIC_RANGES-FRANGE_T WITH KEY DYNAMIC_RANGE2-FIELDNAME
                             
INTO DYNAMIC_RANGE2.

    FLAG_READ
= 'X'.
 
ENDIF.
 
SELECT * FROM SCARR
   
WHERE CARRID IN
S_CARRID
   
AND
CARRNAME IN DYNAMIC_RANGE1-SELOPT_T"使用IN 关键字使用Ranges内表
   
AND CURRCODE IN DYNAMIC_RANGE2-SELOPT_T."(与select-options屏幕参数是一样的用法)
   
PUT SCARR.
 
ENDSELECT
.
ENDFORM.

6.3.4.   FIELD SELECTION动态选择字段

SELECTION-SCREEN FIELD SELECTION FOR NODE|TABLE <node>.语句的作用是开启节点<node>的动态字段选择的功能(形如:SELECT (选择字段内表) FROM…,而不是SELECT * FROM …即选择了哪些字段,就只查询哪些字段,而不是将所有字段查询出来,进而可以提高性能)

在可执行报表程序里,可以通过GET node [FIELDS f1 f2 ...] 语句中的 FIELDS选项来指定要读取字段;

image060

另外,上面LDB数据库程序中要能从SELECT_FIELDS内表读取数据,则必须在LDB选择屏幕里开启相应节点的动态选择字段:

image061

其中,SELECT_FIELDS内表行结构如下:

image062

image063

6.3.4.1.            SELECT_FIELDS

PUT_<node> Form中的SELECT语句中Where从句如果要使用 FIELD SELECTION 动态选择字段时,需要用到数据对象SELECT_FIELDS,在LDB数据库程序中,通过从SELECT_FIELDS内表中就可以读取GET node [FIELDS f1 f2 ...] 语句传递进来的选择字段,SELECT_FIELDSLDB数据库程序自动生成的,其类型如下(不必在LDB程序中加入下面代码行,直接就可以使用SELECT_FIELDS内表,另外在相连的报表程序中也可以使用,这与DYN_SEL不同):

TYPE-POOLS RSFS.
DATA SELECT_FIELDS
TYPE RSFS_FIELDS.

image064

RSDS_FIELDS中的FIELDS里存储的就是GET…FIELDS…语句传递过来的用户指定的查询字段,FIELDS内表可以直接使用在 SELECT…从句中。

 

现假设有名为 ZHK LDBSCARR为该LDB的根节点,且仅有SPFLI一个子节点。LDB选择屏幕 Include文件 DBZHKSEL内容如下:

SELECT-OPTIONS S_CARRID FOR SCARR-CARRID.
SELECT-OPTIONS S_CONNID FOR SPFLI-CONNID
.
"需要先开始动态选择字段功能
SELECTION-SCREEN FIELD SELECTION FOR TABLE SPFLI.

 

LDB数据库程序SAPDBZHK中,PUT_SCARR过程中使用dynamic selection的过程如下:

FORM PUT_SPFLI.
 
STATICS: FIELDLISTS TYPE RSFS_TAB_FIELDS,
           FLAG_READ
."确保SELECT_FIELDS只读取一次
 
IF FLAG_READ = SPACE.
    FIELDLISTS
-TABLENAME = 'SPFLI'
.
    "读取相应表的动态选择字段
   
READ TABLE SELECT_FIELDS WITH KEY FIELDLISTS-TABLENAME INTO FIELDLISTS.
    FLAG_READ
= 'X'.
 
ENDIF.
  SELECT (FIELDLISTS-FIELDS)"动态选择字段
         
INTO CORRESPONDING FIELDS OF SPFLI FROM SPFLI
         
WHERE CARRID = SCARR-CARRID AND CONNID IN S_CONNID.

   
PUT SPFLI.
 
ENDSELECT
.
ENDFORM.

在相应的可执行报表程序里,相应的代码可能会是这样的:

TABLES SPFLI.
GET SPFLI FIELDS
CITYFROM CITYTO.
    ...

GET语句中的FIELDS选项指定了除主键外需要查询来的字段,主键不管是否选择都会被从数据库表中读取出来,可以由下面报表程序中的代码来证明

DATA: ITAB LIKE SELECT_FIELDS,
      ITAB_L
LIKE LINE OF ITAB,
      JTAB
LIKE ITAB_L-FIELDS,
      JTAB_L
LIKE LINE OF JTAB.
START-OF-SELECTION.
  ITAB
= SELECT_FIELDS. "在报表程序中也可以直接使用LDB程序中的全局变量!
 
LOOP AT ITAB INTO ITAB_L.
   
IF ITAB_L-TABLENAME = 'SPFLI'.
      JTAB
= ITAB_L-FIELDS.
     
LOOP AT JTAB INTO JTAB_L.
       
WRITE / JTAB_L.
     
ENDLOOP.
   
ENDIF.
 
ENDLOOP.

如果报表程序中的GET语句是这样的:GET SPFLI FIELDS CITYFROM CITYTO.,则输入结果为:

CITYTO

CITYFROM

MANDT

CARRID

CONNID

可以从输出结果看出,主键MANDTCARRIDCONNID会自动的加入到SELECT_FIELDS内表中,一并会从数据库中读取出来

6.4.  数据库程序中重要FORM

? FORM INIT

在选择屏幕处理前仅调用一次(在PBO之前调用)

? FORM PBO

在选择屏幕每次显示之前调用,即LDB选择屏幕的PBO事件块

? FORM PAI

用户在选择屏幕上输入之后调用,即LDB选择屏幕的PAI事件块(之后?)。

FORM带两个接口参数FNAME and MARK将会传到subroutine 中。FNAME存储了选择屏幕中用户所选择SELECT-OPTIONPARAMETERS屏幕字段名MARK标示了用户选择的是单值还是多值条件:MARK = SPACE意味着用户输入了一个简单单值或者范围取值,MARK = '*'意味着用户在Multiple Selection screen 的输入(即多个条件值)FNAME = '*' MARK = 'ANY'表示所有的屏幕参数都已检验完成,即可以对屏幕整体参数做一个整体的检测了(这里的意思应该就是相当于AT SELECTION-SCREEN)。

? FORM PUT_<node>

最顶层节点<node>所对应的FORM PUT_<node>会在START-OF-SELECTION事件结束后自动被调用,而其他下层节点所对应的FORM会由它的上层节点所对应的FORM中的PUT <node>语句来触发(在上层节点所对应的可执行程序中的相应GET事件块执行之后触发)

PUT <node>.

此语句用是PUT_<node>子过程中的特定语句,它是与PUT_<node> Form一起使用的,通常是放在循环处理数据循环过程中。PUT语句根据LDB的结构指引了报表程序的逻辑。该语句会触发相应的报表程序的GET <node>事件。当GET事件块执行完后,如果有下层节点,则还会调用下层节点所对应的FORM PUT_<node>

PUT语句是该FormPUT_<node>)中最主要的语句:此语句仅仅只能在LDB数据库程序的Form中使用。

PUT_<node>调用结束后,报表程序中相应GET <node> LATE事件块也会自动调用。

 

首先,根节点所对应的PUT_<root>会自动执行,此Form中的PUT <node>会以下面的先后顺序来执行程序:

1.      如果LDB数据库程序包含了AUTHORITY_CHECK_<table>语句,则PUT语句的第一件事就是调用它

2.      然后,PUT语句会触发报表程序相应的GET事件

3.      再后,PUT语句会去调用LDB程序中下一节点的PUT_<node>子过程(此过程又会按照这里的三步来运行),直到下层所有子孙节点PUT_<node>过程处理完成(深度遍历),才会回到最上一层节点的PUT语句

4.      当控制权从下层节点的PUT_<node>返回时,PUT语句还会触发当前节点的GET <node> LATE报表事件

image065

GET事件块会在LDB程序从数据库表中读取到一行数据时被触发

6.5.  LDB选择屏幕:静()态选择屏幕、动态选择视图

image066

image067

image068 image069

在报表选择屏幕上是否显示LDB普通选择条件(即静态的,与动态选择条件相对应),则要看报表程序中是否使用了对应的 TABLE <node>语句,如果有,则与<node>节点相关的所有LDB选择条件都会显示在报表程序的选择屏幕上,如果没有此语句,则与<node>节点相关的所有LDB选择条件都会不会显示(但如果某个节点没有在TABLE语句中进行定义,但其子节点,或子孙节点在TABLE语句中进行了定义,则这些子孙节点所对应的父节点所对应LDB屏幕选择条件还是会嵌入到报表选择屏幕中)。有几种情况:

l  如果报表程序中只有根节点的定义语句:

image070

则报表程序的选择屏幕只会将spfli节点相关的普通选择条件内嵌进来,子孙节点不会显示出来:

image071

l  如果报表程序只有子孙节点定义语句:

image072

则报表程序的选择屏幕中,会将sbook的父节点SFLIGHT以及爷节点SPFLI相关的LDB静态选择内嵌进来

image073

如果LDB的选择屏幕在没有创建选择视图的情况下:动态选择是否显示在报表程序的选择屏幕中,首先要看报表程序中是否使用了 TABLE <node>对需要动态显示的节点进行了定义(如果这个节点是上层节点,则此节点为本身也可以不在TABLE语句定义,而是对其子孙节点进行定义也是可以的),再者,还需要相应的<node>节点在LDB屏幕选择Include程序中的SELECTION-SCREEN DYNAMIC SELECTIONS FOR TABLE <node>语句中进行定义,注:要显示,则对应节点一定要在此语句中定义过,而不是像报表程序中的节点只对其子孙节点进行定义即可,而是谁需要动态显示,则谁就得要在动态定义语句中进行定义,如下面在LDB选择屏幕Include程序中只对SBOOK的上层节点SPFLI,SFLIGHT进行了定义,并没有对SBOOK进行定义:

image074

而在报表程序中只能SBOOK进行了定义:

image075

但最后在报表动态选择屏幕中,只有SPFLI,SFLIGHT两个表的条件(需使用SELECTION-SCREEN DYNAMIC SELECTIONS语句对SPFLI,SFLIGHT节点进行定义),而SBOOK并没有:

image076

在没有创建选择视图的情况下,以表名来建小分类,且动态条件字段为整个表的所有字段

 

如果LDB的选择屏幕在有选择视图的情况下:只要存在选择视图,则只显示选择视图里被选择的字段,其他任何字段一概不显示。下面只将SPFLI-CARRIDSFLIGHT-CONNID两个字段已分别纳入到了0102分组中,而SBOOK节点中没有字段纳入:

image077

image078

报表程序里将SBOOK节点定义在了TABLES语句中,所以,从SBOOK这一级开始(包括)向上所有节点的所对应的字段,如果纳入了选择视图中,则选择屏幕显示如下:

image079

posted @ 2015-01-31 21:06  江正军  阅读(7638)  评论(0编辑  收藏  举报